package com.sys.utils;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

/**
 * @author jack
 *
 */
public class StringUtil {
	private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

	private static SimpleDateFormat fullDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	public static String UTF8 = "UTF-8";
	public static String  GBK = "GBK";
	public static String GB2312 ="GB2312";
	public static String ISO_8859_1 = "ISO-8859-1";

	/**
	 * 转义字符转换
	 * 
	 * @param string
	 * @return
	 */
	public static String quote(String string) {
		if (string == null || string.length() == 0) {
			return "\"\"";
		}

		char b;
		char c = 0;
		int i;
		int len = string.length();
		StringBuffer sb = new StringBuffer(len + 4);
		String t;

		sb.append('"');
		for (i = 0; i < len; i += 1) {
			b = c;
			c = string.charAt(i);
			switch (c) {
			case '\\':
			case '"':
				sb.append('\\');
				sb.append(c);
				break;
			case '/':
				if (b == '<') {
					sb.append('\\');
				}
				sb.append(c);
				break;
			case '\b':
				sb.append("\\b");
				break;
			case '\t':
				sb.append("\\t");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\r':
				sb.append("\\r");
				break;
			default:
				if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
						|| (c >= '\u2000' && c < '\u2100')) {
					t = "000" + Integer.toHexString(c);
					sb.append("\\u" + t.substring(t.length() - 4));
				} else {
					sb.append(c);
				}
			}
		}
		sb.append('"');
		return sb.toString();
	}
	
	
	/**
	 * 对 SQL LIKE 的内容进行转义
	 *
	 * @param str
	 * @return
	 */
	public static String sqlLikeQuote(String str) {
		return str.replace("\\\\", "\\\\\\\\").replace("_", "\\_").replace("%", "\\%");
	}
	
	
	/**
	 * SQL转义字符转换
	 * 
	 * @param string
	 * @return
	 */
	public static String sqlQuote(String string) {
		if (string == null) return string;
		
		if (string.length() == 0) {
			return "''";
		}

		char b;
		char c = 0;
		int i;
		int len = string.length();
		StringBuffer sb = new StringBuffer(len + 4);
		String t;

		sb.append('\'');
		for (i = 0; i < len; i += 1) {
			b = c;
			c = string.charAt(i);
			switch (c) {
			case '\\':
			case '"':
				sb.append('\\');
				sb.append(c);
				break;
			case '\'':
				sb.append('\\');
				sb.append(c);
				break;
			case '/':
				if (b == '<') {
					sb.append('\\');
				}
				sb.append(c);
				break;
			case '\b':
				sb.append("\\b");
				break;
			case '\t':
				sb.append("\\t");
				break;
			case '\n':
				sb.append("\\n");
				break;
			case '\f':
				sb.append("\\f");
				break;
			case '\r':
				sb.append("\\r");
				break;
			default:
				if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
						|| (c >= '\u2000' && c < '\u2100')) {
					t = "000" + Integer.toHexString(c);
					sb.append("\\u" + t.substring(t.length() - 4));
				} else {
					sb.append(c);
				}
			}
		}
		sb.append('\'');
		return sb.toString();
	}

	/**
	 * Pads the left side of a string with a specified character. 
	 * This is especially useful for normalizing number and date strings. Example usage: 
	 * leftPad('123', 5, '0');
	 * // s now contains the string: '00123'
	 * @param val 	The original string
	 * @param size The total length of the output string
	 * @param ch
	 * @return The character with which to pad the original string 
	 */
	public static String leftPad(String val, int size, char ch) {
        StringBuffer sb = new StringBuffer();
        for (int i = val.length(); i < size; i ++) {
			sb.append(ch);
		}
        return sb.append(val).toString();
    }
    
	/**
	 * 转换字符
	 * 
	 * @param o
	 * @return
	 */
	public static String o2s(Object o) {
		if (o == null) {
			return "null";
		}
		// type of String return "+o+"
		if (o instanceof String) {
			return quote((String) o);
		} else if (o instanceof Date) {
			return new Long(((Date) o).getTime()).toString();
		}
		// type of Doubel,Float,Long,Short,Character,Byte,Boolean or other
		// return o;
		if (o instanceof Double || o instanceof Float || o instanceof Long
				|| o instanceof Integer || o instanceof Short
				|| o instanceof Character || o instanceof Byte
				|| o instanceof Boolean) {
			return o.toString();
		}

		return quote(o.toString());
	}

	/**
	 * 转换字符,组成K,V模式
	 * 
	 * @param key
	 * @param o
	 * @return
	 */
	public static String o2kv(String key, Object o) {
		return o2s(key) + " : " + o2s(o);
	}

	public <X> X nvl(X o, X overrideNullValue) {
		if (o == null) {
			return (X) overrideNullValue;
		} else {
			return (X) o;
		}
	}

	public static String nvlS(String s) {
		if (s == null) {
			return "";
		} else {
			return s;
		}
	}

	public static Long nvlL(Long l) {
		if (l == null) {
			return 0L;
		} else {
			return l;
		}
	}

	public static Integer nvlI(Integer i) {
		if (i == null) {
			return 0;
		} else {
			return i;
		}
	}

	/**
	 * Truncate a string and add an ellipsis ('...') to the end if it exceeds
	 * the specified length
	 * 
	 * @param s
	 *            The string to truncate
	 * 
	 * @param len
	 *            The maximum length to allow before truncating
	 * 
	 * @return
	 */
	public static String ellipsis(String s, int len) {
		if (s == null) {
			return "";
		}
		if (s.length() > len) {
			return s.substring(0, len - 3) + "...";
		}
		return s;
	}

	/**
	 * Converts the first character only of a string to upper case
	 * 
	 * @param s
	 *            value The text to convert
	 * @return The converted text
	 */
	public static String capitalize(String s) {
		if (s == null || s.length() == 1) {
			return s;
		}

		return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
	}

	/**
	 * Format a number as system default local currency
	 * 
	 * @param d
	 *            value The numeric value to format
	 * @return The formatted currency string
	 */
	public static String usMoney(Double d) {
		NumberFormat nf = NumberFormat.getCurrencyInstance();
		return nf.format(nf);
	}

	/**
	 * Format a number as local currency
	 * 
	 * @param d
	 *            value The numeric value to format
	 * @param locale
	 * @return The formatted currency string
	 */
	public static String usMoney(Double d, Locale locale) {
		NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
		return nf.format(nf);
	}
	
	public static String usInteger(Number d) {
		NumberFormat nf = NumberFormat.getIntegerInstance();
		return nf.format(d);
	}
	
	public static String usNumber(Number d) {
		NumberFormat nf = NumberFormat.getNumberInstance();
		return nf.format(d);
	}

	/**
	 * Simple format for a file size (xxx bytes, xxx KB, xxx MB)
	 * 
	 * @param size
	 *            The numeric value to format
	 * @return The formatted file size
	 */
	public static String fileSize(Long size) {
		if (size < 1024) {
			return size + " bytes";
		} else if (size < 1048576) {
			return (Math.round(((size * 10) / 1024)) / 10) + " KB";
		} else {
			return (Math.round(((size * 10) / 1048576)) / 10) + " MB";
		}
	}

	/**
	 * 判断字符是否为空
	 * 
	 * @param s
	 * @return
	 */
	public static boolean isEmpty(String s) {
		return s == null || s.trim().equals("");
	}

	/**
	 * 格式化日�? (yyyy-MM-dd HH:mm:ss)
	 * 
	 * @param date
	 * @return 日期
	 */
	public static String formatFullDate(Date date) {
		String dateString = fullDateFormat.format(date);
		return dateString;
	}

	/**
	 * 格式化日�? (yyyy-MM-dd)
	 * 
	 * @param date
	 * @return 日期
	 */
	public static String formatShortDate(Date date) {
		String dateString = dateFormat.format(date);
		return dateString;
	}

	/**
	 * Parse a string using the full/short format pattern.
	 * 
	 * @param s
	 * @return
	 * @throws ParseException
	 */
	public static Date parseDate(String s) throws ParseException {
		if (s == null || s.equals("")) {
			throw new NullPointerException("Date string is null");
		} else if (s.length() == dateFormat.toPattern().length()) {
			return dateFormat.parse(s);
		} else if (s.length() == fullDateFormat.toPattern().length()) {
			return fullDateFormat.parse(s);
		} else {
			throw new ParseException(s, 0);
		}
	}

	/**
	 * 将字符串用MD5算法加密
	 * 
	 * @param string
	 * @return 加密后的字符�?
	 */
	public static String getMD5Encryption(String string) {
		byte[] source = string.getBytes();
		String s = null;
		char hexDigits[] = { // 用来将字节转换成 16 进制表示的字�?
		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
				'e', 'f' };
		try {
			java.security.MessageDigest md = java.security.MessageDigest
					.getInstance("MD5");
			md.update(source);
			byte tmp[] = md.digest(); // MD5 的计算结果是�?�? 128 位的长整数，
			// 用字节表示就�? 16 个字�?
			char str[] = new char[16 * 2]; // 每个字节�? 16 进制表示的话，使用两个字符，
			// �?以表示成 16 进制�?�? 32 个字�?
			int k = 0; // 表示转换结果中对应的字符位置
			for (int i = 0; i < 16; i++) { // 从第�?个字节开始，�? MD5 的每�?个字�?
				// 转换�? 16 进制字符的转�?
				byte byte0 = tmp[i]; // 取第 i 个字�?
				str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字节中�? 4 位的数字转换,
				// >>> 为�?�辑右移，将符号位一起右�?
				str[k++] = hexDigits[byte0 & 0xf]; // 取字节中�? 4 位的数字转换
			}
			s = new String(str); // 换后的结果转换为字符�?

		} catch (java.security.NoSuchAlgorithmException e) {
			e.printStackTrace();
			throw new RuntimeException("getMD5 Error! errors :"
					+ e.getMessage());
		}
		return s;
	}

	public static String format(String s, Map<String, Object> assign) {
		if (isEmpty(s) || assign == null) {
			return s;
		}
		StringBuilder sb = new StringBuilder(s.length() + 500);
		int fromIndex = 0;
		while (true) {
			int keyStart = s.indexOf("{", fromIndex), keyEnd = s.indexOf("}", fromIndex);
			if (keyStart == -1 || keyEnd == -1) {
				sb.append(s.substring(fromIndex));
				break;
			} 
			
			String prefix = s.substring(fromIndex, keyStart);
			String key = s.substring(keyStart + 1, keyEnd);
			
			sb.append(prefix);
			if (assign.containsKey(key)) {
				sb.append(assign.get(key));
			}
			fromIndex = keyEnd + 1;
		}
		return sb.toString();
	}
	
	
	public static String format(String s, Serializable... args) {
		if (isEmpty(s) || args == null) {
			return s;
		}
		StringBuilder sb = new StringBuilder(s.length() + 500);
		int fromIndex = 0;
		while (true) {
			int keyStart = s.indexOf("{", fromIndex), keyEnd = s.indexOf("}", fromIndex);
			if (keyStart == -1 || keyEnd == -1) {
				sb.append(s.substring(fromIndex));
				break;
			} 
			
			String prefix = s.substring(fromIndex, keyStart);
			String key = s.substring(keyStart + 1, keyEnd);
			
			sb.append(prefix);
			if (isInt(key)) {
				int index = Integer.parseInt(key);
				if (index >= 0 && index < args.length) {
					Serializable value = args[index];
					sb.append(value);
				}
			}
			fromIndex = keyEnd + 1;
		}
		return sb.toString();
	}

	/**
	 * 判断字符串是否由0-9的数字组成.
	 * 
	 * @param string
	 * @return
	 */
	public static boolean isDigitComponent(String string) {
		if (isEmpty(string)) {
			return false;
		}
		for (Character c : string.toCharArray()) {
			if (!Character.isDigit(c)) {
				return false;
			}
		}
		return true;
	}
  
	/**
	 * 判断字符串是否由0-9, A-Z, a-z的数字组成.
	 * 
	 * @param string
	 * @return
	 */
	public static boolean isLetterOrDigitComponent(String string) {
		if (isEmpty(string)) {
			return false;
		}

		for (Character c : string.toCharArray()) {
			if (!Character.isLetterOrDigit(c) || c > 128) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 判断字符串是否由A-Z, a-z的数字组成.
	 * 
	 * @param string
	 * @return
	 */
	public static boolean isLetterComponent(String string) {
		if (isEmpty(string)) {
			return false;
		}

		for (Character c : string.toCharArray()) {
			if (!Character.isLetter(c) || c > 128) {
				return false;
			}
		}
		return true;
	}

	/**
	 *  判断字符串是不是整数.
	 * @param s
	 * @return
	 */
	public static boolean isInt(String s) {
		if (isEmpty(s)) {
			return false;
		}
		try {
			Integer.parseInt(s);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}
	
	
	/**
	 *  判断字符串是不是双精度数.
	 * @param s
	 * @return
	 */
	public static boolean isDouble(String s) {
		if (isEmpty(s)) {
			return false;
		}
		try {
			Double.parseDouble(s);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}
	/**
	 * 日期函数。
	 * @param desc 原始日期
	 * @param offsetDays 向前或向后移动多少天
	 * @param clearTime	true 把时间设置为00:00:00 false 返回desc time.
	 * @return
	 */
	public static Date dateOffset(Date desc, int offsetDays, boolean clearTime) {
		long startTime = desc.getTime();
		long day = 3600000 * 24;
		long toTime = startTime + offsetDays * day;
		if (clearTime) {
			if ((startTime + TimeZone.getDefault().getOffset(toTime)) % day == 0) {
			} else {
				toTime -= startTime % day;							// clear time;
				toTime -=  TimeZone.getDefault().getOffset(toTime); // set TimeZone.
			}
		}
		Date toDate = new Date(toTime);
		return toDate;
	}
	
	/**
	 * 生成随机字符串[A-Z,a-z,0-9].
	 * @param length 长度
	 * @return
	 */
	public static String generateStr (int length) {
		String allowChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
		StringBuffer sb = new StringBuffer(length);
		for (int i = 0; i < length; i++) {
			int charIndex = (int) ((Math.random() * 10000) % allowChars.length());
			sb.append(allowChars.charAt(charIndex));
		}
		return sb.toString();
	}
	
	/**
	 * 生成随机数量字符串[0-9].
	 * @param length 长度
	 * @return
	 */
	public static String generateDigit (int length) {
		String allowChars = "1234567890";
		StringBuffer sb = new StringBuffer(length);
		for (int i = 0; i < length; i++) {
			int charIndex = (int) ((Math.random() * 10000) % allowChars.length());
			sb.append(allowChars.charAt(charIndex));
		}
		return sb.toString();
	}
	
	/**
	 * Rounds the argument x to d decimal places. 
	 * The rounding algorithm depends on the data type of x. d 
	 * defaults to 0 if not specified. d can be negative 
	 * to cause d digits left of the decimal point of the
	 * value x to become zero.
	 * @param d
	 * @return
	 */
	public static double round(double x, int d) {
		double b = Math.pow(10, d);
		return (Math.round(x * b) + 0D) / b; 
	}
	
	/**
	 * 测试tests是否包含test.
	 * @param test 测试的值.
	 * @param tests 测试的范围.
	 * @return
	 */
	public static boolean testIn(Serializable test, Serializable ... tests) {
		for (Serializable t : tests) {
			if ((t == null || test == null ) || t.equals(test)) {
				return true;
			}
		}
		return false;
	}
	public static String httpPOST (String url, String charset) {
		
		URL url_ = null;
		HttpURLConnection connection = null;

		try {
			//建立连接
			url_ = new URL(url);
			connection = (HttpURLConnection) url_.openConnection();
			connection.setDoOutput(true);
			connection.setDoInput(true);
			//connection.setRequestMethod("POST");
			connection.setUseCaches(false);
			connection.connect();

			//传递参数
			DataOutputStream out = new DataOutputStream(connection.getOutputStream());
			// 用utf-8的编码方式传递参数，否则中文会出现乱码
			//out.write(content.getBytes("utf-8"));
			out.flush();
			out.close();

			//获得返回结果
			BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(),charset));
			StringBuffer buffer = new StringBuffer();
			String line = "";
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
			reader.close();
			return buffer.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (connection != null) {
				connection.disconnect();
			}
		}
		return null;
	}
	
	/**
     * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
     * @param {String} value The string to encode
     * @return {String} The encoded text
     */
    public static String htmlEncode (String value){
        return value.replace("&", "&amp;").replace(">", "&gt;").replace("<", "&lt;").replace("\"", "&quot;");
    };

    /**
     * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
     * @param {String} value The string to decode
     * @return {String} The decoded text
     */
    public static String htmlDecode(String value){
        return value.replace("&gt;", ">").replace("&lt;", "<").replace("&quot;", "\"").replace("&amp;", "&");
    }
    
    
    /**
     * Converts newline characters to the HTML tag &lt;br/>
     * @param {String} The string value to format.
     * @return {String} The string with embedded &lt;br/> tags in place of newlines.
     */
    public static String nl2br(String v){
        return v.replaceAll("\r?\n", "<br/>");
    }
    
	
	public static String httpPOST(String url, Map<String, Object> properties, String characterEncoding) {
		StringBuilder param = new StringBuilder();
		for (String key : properties.keySet()) {
			param.append("&").append(key).append("=").append(properties.get(key));
		}
		String content = param.toString().substring(1);
		
		URL url_ = null;
		HttpURLConnection connection = null;

		try {
			//建立连接
			url_ = new URL(url);
			connection = (HttpURLConnection) url_.openConnection();
			connection.setDoOutput(true);
			connection.setDoInput(true);
			connection.setRequestMethod("POST");
			connection.setUseCaches(false);
			connection.connect();

			//传递参数
			DataOutputStream out = new DataOutputStream(connection.getOutputStream());
			// 用utf-8的编码方式传递参数，否则中文会出现乱码
			out.write(content.getBytes(characterEncoding));
			out.flush();
			out.close();

			//获得返回结果
			BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), characterEncoding));
			StringBuffer buffer = new StringBuffer();
			String line = "";
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
			reader.close();
			return buffer.toString();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (connection != null) {
				connection.disconnect();
			}
		}
		return null;
	}
}
